function gameObject(id, player, tileX, tileY, images, goName, template, map) {
	this.id = id;
	this.player = player;	
	this.x = tileX * map.tileSize;
	this.y = tileY * map.tileSize;
	this.xDir = 0;
	this.yDir = 0;
	this.idleImage = images[goName+'Idle'+player.id];
	this.attackImage = images[goName+'Attack'+player.id];
	for(var templateProperty in template) {
		this[templateProperty] = template[templateProperty];
	}
	this.rangeSquared = this.range*this.range;
    this.attackTimer = 0;
	this.map = map;
	this.nextTile = this.map.tiles[Math.floor(this.x / this.map.tileSize)][Math.floor(this.y / this.map.tileSize)];
	for(var i = tileX; i < tileX + this.width / map.tileSize; i++) {
        for(var j = tileY; j < tileY + this.height / map.tileSize; j++) {
            map.tiles[i][j].occupiedBy = this;
			if(this.moveSpeed === 0) {
				map.tiles[i][j].passable = false;
			}
        }
    }
	this.destroyed = [];

	this.sqrt2Over2 = 0.707106781;

	this.buildQueue = [];
	this.buildTimer = 0;
	this.maxQueue = 5;
}

gameObject.prototype.moveTo = function(tileX, tileY) {
	this.final_destination_tile_x = tileX;
	this.final_destination_tile_y = tileY;
}

gameObject.prototype.move = function() {
	if(this.moveSpeed > 0) {
		if(Math.abs(this.x - this.nextTile.x * this.map.tileSize) < this.moveSpeed && Math.abs(this.y - this.nextTile.y * this.map.tileSize) < this.moveSpeed) {
			this.x = this.nextTile.x * this.map.tileSize;
			this.y = this.nextTile.y * this.map.tileSize;
			this.xDir = 0;
			if(Math.abs(this.final_destination_tile_x * this.map.tileSize) > this.x) {
				this.xDir = 1;
			}
			else if(Math.abs(this.final_destination_tile_x * this.map.tileSize) < this.x) {
				this.xDir = -1;
			}

			this.yDir = 0;
			if(Math.abs(this.final_destination_tile_y * this.map.tileSize) > this.y) {
				this.yDir = 1;
			}
			else if(Math.abs(this.final_destination_tile_y * this.map.tileSize) < this.y) {
				this.yDir = -1;
			}
			
			var nextTile = this.map.tiles[this.x / this.map.tileSize + this.xDir][this.y / this.map.tileSize + this.yDir];
			if(nextTile.passable && nextTile.occupiedBy === null) {
				this.nextTile.occupiedBy = null;
				nextTile.occupiedBy = this;
				this.nextTile = nextTile;
			}
			else {
				this.xDir = 0;
				this.yDir = 0;
			}

			if(this.xDir !== 0 && this.yDir !== 0) {
				this.xDir *= this.sqrt2Over2;
				this.yDir *= this.sqrt2Over2;
			}
		}

		this.x += this.xDir * this.moveSpeed;
		this.y += this.yDir * this.moveSpeed;
	}
}

gameObject.prototype.attack = function(collisionEngine) {
    if(this.damage === 0) return;
	if(!this.target) {
		var collidedWith = collisionEngine.checkForCollisions(this);
		if(collidedWith.length > 0) {
			for(var i = 0; i < collidedWith.length; i++) {
				var c = collidedWith[i];
				if(c.player !== this.player) {
					this.target = c;
					c.destroyed.push({caller: this, fn: this.targetDestroyed});
					break;
				}
			}
		}
	}
	
	if(this.target) {
		if(this.inRange(this.target)) {
            if(this.attackTimer <= 0) {
                this.target.takeDamage(this.damage);
                this.attackTimer = this.attackSpeed;
            }
		}
		else {
			this.target.destroyed.remove(this.targetDestroyed);
            this.target = null;
		}
	}
	this.attackTimer -= 1000 / game.fps / 1000;
}

gameObject.prototype.inRange = function(other) {
	var left = this.x - this.range;
	var right = this.x + this.width + this.range;
	var top = this.y - this.range;
	var bottom = this.y + this.height + this.range;

	if(bottom < other.y || top > other.y + other.height || right < other.x || left > other.x + other.width) {
		return false;
	}
	return true;
}

gameObject.prototype.takeDamage = function(amount) {
	this.health -= amount;

	if(this.health <= 0) {
        this.nextTile.occupiedBy = null;
        var tileX = Math.floor(this.x / this.map.tileSize);
        var tileY = Math.floor(this.y / this.map.tileSize);
        for(var i = tileX; i < tileX + this.width / this.map.tileSize; i++) {
            for(var j = tileY; j < tileY + this.height / this.map.tileSize; j++) {
                this.map.tiles[i][j].occupiedBy = null;
				if(this.moveSpeed === 0) {
					this.map.tiles[i][j].passable = true;
				}
            }
        }
		for(var i = 0; i < this.destroyed.length; i++) {
			this.destroyed[i].fn(this.destroyed[i].caller, this);
		}
		if(this.target) {
			this.target.destroyed.remove(this.targetDestroyed);
		}
        this.target = null;
	}
}

gameObject.prototype.targetDestroyed = function(self, target) {
	self.target = null;
}

gameObject.prototype.queueUnit = function(template) {
	if(this.buildQueue.length < this.maxQueue && template.price <= this.player.credits) {
		this.player.credits -= template.price;
		if(this.buildQueue.length === 0) {
			this.buildTimer = template.buildTime;
		}
		this.buildQueue.push(template);
	}
}

gameObject.prototype.cancelUnit = function(index) {
	if(this.buildQueue.length > index) {
		this.player.credits += this.buildQueue[index].price;
		this.buildQueue.splice(index, 1);
		if(index === 0) {
			this.buildTimer = this.buildQueue[0] ? this.buildQueue[0].buildTime : 0;
		}
	}
}

gameObject.prototype.build = function() {
	if(this.buildQueue.length > 0) {
		if(this.buildTimer <= 0) {
			var template = this.buildQueue.shift();
			game.createGameObject(template, this.player, this.x / this.map.tileSize + 1, this.y / this.map.tileSize + 3);
			this.buildTimer = this.buildQueue[0] ? this.buildQueue[0].buildTime : 0;
		}
		this.buildTimer -= 1000 / game.fps / 1000;
	}
}
